#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include "lexical.h"
#include "error.h"
#include "parser.h"
#include "gp_list.h"
#include "symbol.h"
#include "sym_table.h"
#include "semantic.h"
#include "common.h"
#include "token_list.h"


tk_node_t *cur_tk_g = NULL;


void next_token(void);
bool match(symbol_e need);
void syntax_analyse(void);
void program(void);
void subprogram(void);
symbol_e type(void);
static symbol_e get_op(void);
static void parser_get_token_id(char *name);
void decl(bool is_ext, symbol_e my_type, int scope);
void fun_body(int scope, symbol_e type, bool ptr, const char *name, 
		struct list_head *para_list_head, int line);
void var_decl_tail(bool is_ext, symbol_e my_type, bool is_ptr, 
        const char *name, int line);
int arr_len(const char *name);

void *primary_expr(int *sym_type);
void arglist(void);
void arg(void);
void realarg(void);
var_t *literal(void);
var_t *post_expr(void);
var_t *unary_expr(void);
var_t *mul_tail(var_t *lval);
var_t *mul_expr(void);
var_t *add_tail(var_t *lval);
var_t *add_expr(void);
var_t *relation_tail(var_t *lval);
var_t *relation_expr(void);
var_t *equ_tail(var_t *lval);
var_t *equ_expr(void);
var_t *logical_and_tail(var_t *lval);
var_t *logical_and_expr(void);
var_t *logical_or_tail(var_t *lval);
var_t *logical_or_expr(void);
var_t *assign_tail(var_t *lval);
var_t *assign_expr(void);
var_t *expr(void);
void ele(var_t *arr);
void arr_init_list(var_t *arr);
void var_init(int arr_len, bool is_ext, symbol_e my_type, bool is_ptr,
          const char *name, int line);

void global_decl(void);
void fun_decl_tail(symbol_e my_type, bool ptr, const char *name,
                   int scope, int line);

void var_item(bool is_ext, symbol_e my_type);
void var_list(bool is_ext, symbol_e my_type);
struct list_head *para_decl(void);
void para_item(struct list_head *params_head);
void para_list(struct list_head *params_head);
void elements(var_t *arr);
void next_token(void);
void block(void);
void case_label(void);
void elements_tail(var_t *arr);
void case_stat(void);
void switch_stat(void);
void else_stat(void);
void statement(void);
void while_stat(void);
void for_stat(void);
void do_while_stat(void);
void for_init(void);
void for_cond(void);
void for_iter(void);
void if_stat(void);
bool array_semantic_check(var_t *arr, int init_method, const char *str);

var_t *gen_1_op_right(var_t *val, symbol_e opt)
{
    return NULL;
}

var_t *gen_1_op_left(var_t *val, symbol_e opt)
{
    return NULL;
}

var_t* gen_2_op(var_t *lval, symbol_e opt, var_t* rval)
{
    return NULL;
}
var_t *gen_arr(var_t *array, var_t *index)
{
    return NULL;
}

static symbol_e get_op(void)
{
    symbol_e op = parser_get_cur_token();
    next_token();
    return op;
}

static void parser_get_token_id(char *name) 
{ 
	strncpy(name, cur_tk_g->pval, MAX_ID_LEN); 
}

symbol_e parser_get_cur_token(void) 
{ 
    return cur_tk_g->tk; 
}

const char *parser_get_token_str(void) 
{ 
    return (const char *)cur_tk_g->pval; 
}

const char parser_get_token_ch(void) 
{ 
    return *(const char *)cur_tk_g->pval; 
}

const int parser_get_token_num(void) 
{ 
    return *(const int *)cur_tk_g->pval; 
}

const int parser_get_token_line_num(void)
{
    return cur_tk_g->line;
}

const int parser_get_token_col_num(void)
{
    return cur_tk_g->col;
}

bool match(symbol_e need)
{
    if (TEST(need)) {
        next_token();
        return true;
    } else {
        return false;
    }
}


void next_token(void)
{
    if(list_empty(&tk_buffer_g)) {
        get_token();
        while (scanner_get_cur_token() == COMMENT || 
                    scanner_get_cur_token() == INVALID) {
            get_token();
        }
        move_token_to_buffer(); 
    }

    cur_tk_g = token_dequeue(&tk_buffer_g); // 出队
    assert(cur_tk_g);
    list_add_tail(&cur_tk_g->entry, &tk_uesd_g);
}


void syntax_analyse(void)  // 语法分析的入口
{
    check_symbol_num();
    next_token(); // 预先读入
    program();
}

/*
    <program> -> <global_decl> <program> | ε
*/
void program(void)
{
    if (TEST(FILE_END)) { // 文件结束
        return;
    } else {
        global_decl();
        program(); // 递归
    }
}

/*
    <type> -> int | char | void
*/
symbol_e type(void)
{
    symbol_e my_type = INVALID; 
    if (TYPE_FIRST) {
        my_type = parser_get_cur_token(); // 记录类型
        next_token();      // 读入下一个符号
    }
    else { 
        // 报错 follow(<type>) = {ident, mul}
        recovery(TEST(ID) OR(MUL), EXPECTED_TYPE, ERROR); 
    }
    return my_type;
}

/*
    <global_decl> -> extern <type> <decl>
                   | <type> <decl>
*/
void global_decl(void)
{
    bool ext = match(EXTERN); 
    symbol_e my_type = type();
    decl(ext, my_type, SCOPE_GLOBAL);
}

// 为了代码复用， local_decl 也调用 decl, 但是参数不一样，最终影响 <fun_body>
void local_decl(void)
{
    bool ext = match(EXTERN); 
    symbol_e my_type = type();
    decl(ext, my_type, SCOPE_LOCAL);
}


/*
    不支持混合声明。这样写虽然符合语法，但是可读性不好。例如：
    int foo1(int a),foo2(char b);
    int m,n,foo3(void);
*/

/*
    <decl>  ->  mul ident <decl_tail>
             |  ident <decl_tail>
    <decl_tail> -> <var_decl_tail> | <fun_decl_tail>
	
*/
void decl(bool is_ext, symbol_e my_type, int scope)
{
    char name[MAX_ID_LEN + 1] = {0};
    bool is_ptr = false;
    int line = -1;
    if (match(MUL)) { // 指针
        is_ptr = true;
    }

    if (TEST(ID)) {
        parser_get_token_id(name);
        line = parser_get_token_line_num();
        next_token();
    } else {
        // error: expected identifier
        recovery(DECL_HEAD_FOLLOW, EXPECTED_ID, ERROR); 
    }

    if (TEST(LPAREN)) {      
	    if(is_ext){	// 不需要 extern
		    // 'extern' keyword on function definition has no effect
		    sem_err(EXTERN_ON_FUNCTION_DEF, WARNING, name, NULL);  
	    }
        fun_decl_tail(my_type, is_ptr, name, scope, line);
    } else {
        var_decl_tail(is_ext, my_type, is_ptr, name, line);
    }
}

/*
    <var_decl_tail> -> <arr_len> <var_init> <var_list>
    
*/
void var_decl_tail(bool is_ext, symbol_e my_type, bool is_ptr, const char *name, int line)
{
    int len = arr_len(name);
    var_init(len, is_ext, my_type, is_ptr, name, line); 
    var_list(is_ext, my_type);
}


/*
	<arr_len> -> lbracket num rbracket 
	           | lbracket  rbracket 
	           | ε
*/
// 不支持变长数组！
int arr_len(const char *name)
{
    int len = NOT_ARR;
    if (match(LBRACKET)) { // 左方括号
        if (TEST(NUM)) { // 用 TEST 不用 match 是因为要获得数组长度
            len = parser_get_token_num();           
            if (len <= 0) { // 因为不支持常量表达式，所以解析不了负数，TODO      
                syn_err(ARR_SIZE_NEGATIVE_OR_ZERO, ERROR, OTHER, name);
				len = ARR_SIZE_INVALID;
            }
			next_token();
        } else {
            if (match(RBRACKET)) { // []
                len = ARR_SIZE_UNKNOWN;
                return len;
            } else { // 例如 int a[x];
                syn_err(ARR_SIZE_NO_CONSTANT, ERROR, OTHER, name);
				len = ARR_SIZE_INVALID;
                // next_token();
                expr();// 比 next_token() 更健壮，可以处理类似 [x+3]
                // todo 如何处理常量表达式
            }
        }
        if (!match(RBRACKET)) { // follow(<arr_len>) = {assign, comma, semico, rparen}
            recovery(TEST(COMMA)OR(SEMICO)OR(ASSIGN)OR(RPAREN), EXPECTED_RBRACKET,
                     ERROR); // expected ‘]’ before ‘;’
        }
    }
    return len; 
}

/*
    <var_init> 	-> assign <init_expr>  | ε
    <init_expr> -> <expr> | <arr_init_list>
*/

void var_init(int arr_len, bool is_ext, symbol_e my_type, bool is_ptr,
          const char *name, int line)
{
    var_t *init_val = NULL; // 默认没有初始化部分
    var_t *var = NULL;
    if (match(ASSIGN)) {
        if (arr_len != NOT_ARR) { // 是数组
            var = new_arr(is_ext, my_type, is_ptr, name, arr_len, line);  
            arr_init_list(var); // 里面可能会 add_var()
            return;
        } else {
            init_val = expr();
        }
    }

    if (arr_len != NOT_ARR) { // 是数组但是没有初始化器
        if(arr_len == ARR_SIZE_UNKNOWN) {
            sem_err(ARRAY_SIZE_MISSING, ERROR, name, NULL); 
            return;
        }
        var = new_arr(is_ext, my_type, is_ptr, name, arr_len, line);  
    } else {
        var = new_var(is_ext, my_type, is_ptr, name, init_val, line);  
    }
    add_var(var);
}


/*
	<var_list> -> comma <var_item> <var_list> | semico
*/
void var_list(bool is_ext, symbol_e my_type)
{
    if (match(COMMA)) {
        var_item(is_ext, my_type);
        var_list(is_ext, my_type);
    } else if (match(SEMICO)) {
        return;
    } else {  // 出错了
        if (TEST(ID)OR(MUL)) { // 逗号丢失
            recovery(true, EXPECTED_COMMA, ERROR);
            var_item(is_ext, my_type); // 让解析回到正轨
            var_list(is_ext, my_type);
        } else { // expected ';'  
            recovery(VAR_LIST_FOLLOW, EXPECTED_SEMICOLON, ERROR);                  
        }
    }
}

/*
	<var_item> ->  ident <arr_len> <var_init> 
                |  mul ident <arr_len> <var_init>
*/
void var_item(bool is_ext, symbol_e my_type)
{
    char name[MAX_ID_LEN + 1] = {0};
    bool is_ptr = false;
    int line;
    if (match(MUL)) { // 指针
        is_ptr = true;
    }

    if (TEST(ID)) {
        parser_get_token_id(name);
        line = parser_get_token_line_num();
        next_token();
    } else {
        recovery(TEST(SEMICO) OR(COMMA) OR(ASSIGN) OR(LBRACKET), EXPECTED_ID,
                 ERROR);
    }
  
    int len = arr_len(name); 
    var_init(len, is_ext, my_type, is_ptr, name, line);
}



/*
 	<fun_decl_tail> -> lparen <para_decl> rparen <fun_body>
*/
void fun_decl_tail(symbol_e my_type, bool ptr, 
                const char *name, int scope, int line)
{
    match(LPAREN); // 调用它的函数已经检查了
    scope_enter();
    struct list_head *params = para_decl(); 
    if (!match(RPAREN))
        recovery(TEST(LBRACES) OR(SEMICO), EXPECTED_RPAREN,
                 ERROR); // error: expected ‘)’
   
    fun_body(scope, my_type, ptr, name, params, line);
    scope_leave();
}


/*
    <para_decl> -> void 
	            |  <para_item> <para_list>
				|  ε
*/
struct list_head *para_decl(void)
{
  
	if(TEST(RPAREN)) // 例如 fun()
		return NULL; // 参数为空

    if (match(VOID)) {
        if (TEST(RPAREN)) {
            return NULL; // 例如 fun(void)
        } else {
            put_token_back(2);  // 把记号放回去，例如 void a
            next_token(); // 必须有，更新  cur_tk_g 指针             
        }
    }

    struct list_head *params_head = malloc(sizeof(struct list_head)); // 记得释放内存
    
	if(!params_head){
		SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
	}
	INIT_LIST_HEAD(params_head);
    para_item(params_head);
    para_list(params_head);
    return params_head;
}



/*
    <para_item> -> <type> ident <arr_len> 
	            |  <type> mul ident <arr_len>
*/
void para_item(struct list_head *params_head)
{
    char name[MAX_ID_LEN + 1] = {0};
    symbol_e my_type = type();
    bool is_ptr = false;
    int line = -1;
    if (match(MUL)) { // 指针
        is_ptr = true;
    }

    if (TEST(ID)) {
        parser_get_token_id(name);
        line = parser_get_token_line_num();
        next_token();
    } else {
        recovery(TEST(COMMA) OR(RPAREN) OR(LBRACKET), EXPECTED_ID, ERROR);
    }

    if (arr_len(name) != NOT_ARR) { // 参数是数组
        is_ptr = true; // 作为指针处理
    }

    var_t *var = new_var(false, my_type, is_ptr, name, NULL, line);  
    if(var) {
        add_var(var);
        // 小心：如果 var 指向的内存释放，可能会造成非法访问
        gp_node_add_tail(var, params_head); 
    }
}

/*
    <para_list> -> comma <para_item> <para_list> |  ε

*/
void para_list(struct list_head *params_head)
{
    if (match(COMMA)) {
        para_item(params_head);
        para_list(params_head); // 递归
    }
}

/*
    SCOPE_GLOBAL:    <fun_body> -> <block> | semico
    SCOPE_LOCAL:     <fun_body> ->  semico
*/

void fun_body(int scope, symbol_e my_type, 
            bool ptr, const char *name, 
            struct list_head *para_list_head, int line)
{
    if (scope == SCOPE_LOCAL) {
        if (!match(SEMICO)) {   // 错误处理 
            if (TEST(LBRACES)) { // forbids nested functions
                // todo 如何获得外层函数名？
                syn_err(FORBIDS_NESTED_FUNCTIONS, ERROR, OTHER, name); 
                // 根据 <subprogram> 的产生式，后续会以 <block> 处理                
            } else {
                recovery(LOCAL_DECL_FOLLOW, EXPECTED_SEMICOLON, ERROR);
            }	
            fun_params_destroy(para_list_head); // 为了简单，不加入函数表
		    free(para_list_head);
            			
        } else {
            // 函数声明  
            fun_t* fun = new_fun(my_type, ptr, 
                        name, para_list_head, line); 
            decl_fun(fun); // 里面有添加到符号表
        }
    } else {
        fun_t* fun = new_fun(my_type, ptr, name, 
                    para_list_head, line); 
        if (match(SEMICO)) { // 函数声明  
            decl_fun(fun); // 里面有添加到符号表
        } else { // 函数定义
            def_fun(fun);
            block();// 注意，这里面没有 scope_enter
            sym_tab_g.cur_fun = NULL; // 当前分析的函数置空	
        } 
    }
}

/*
	<elements> ->  <ele> <elements_tail>
	
*/
void elements(var_t *arr)
{
    ele(arr);
    elements_tail(arr);
}

/*
    <arr_init_list> -> lbraces <elements> rbraces
                     |  STRING
*/

void arr_init_list(var_t *arr)
{
    if(TEST(STRING)) {
        if(arr) {
            bool res = array_semantic_check(arr, 
                    INIT_BY_STRING, parser_get_token_str());
            res ? add_var(arr) : var_destroy(arr);  
        }
        next_token();
        return;
    }

    if (!match(LBRACES)) {
        recovery(EXPR_FIRST, EXPECTED_LBRACES, ERROR);
    }

    elements(arr);

    if(arr) {
        bool res = array_semantic_check(arr, INIT_BY_LIST, NULL);
        res ? add_var(arr) : var_destroy(arr);
    }
    if (!match(RBRACES)) {
        recovery(TEST(COMMA) OR(SEMICO), EXPECTED_RBRACES, ERROR);
    }
}


/*
	<elements_tail> -> comma <ele> <elements_tail> | ε
*/
void elements_tail(var_t *arr)
{
    if (match(COMMA)) {
        ele(arr);
        elements_tail(arr);
    }
}

/*
    <ele> ->  <expr>
*/
void ele(var_t *arr) 
{ 
	var_t *var = expr(); 

	if(var && arr) {
 		gp_node_add_tail(var, &arr->arr_init_val);
	} 
}

/*
    <expr> -> <assign_expr>
*/

var_t *expr(void) 
{ 
    return assign_expr(); 
}

/*
    <assign_expr>	->	<logical_or_expr> <assign_tail>
*/
var_t *assign_expr(void)
{
    var_t *lval = logical_or_expr();
    return assign_tail(lval);
}

/*
    <assign_tail>	->	assign  <assign_expr>
                     |  ε
*/
// 因为赋值运算符的结合性是从右到左，所以 <assign_expr> 是一个整体，要先求值
var_t *assign_tail(var_t *lval)
{
    if (match(ASSIGN)) {
        var_t *rval = assign_expr();
        var_t *res = gen_2_op(lval, ASSIGN, rval);
        return res;
       
    }
    return lval;
}

/*
    <logical_or_expr>  -> 	<logical_and_expr> <logical_or_tail>
*/
var_t *logical_or_expr(void)
{
    var_t *lval = logical_and_expr();
    return logical_or_tail(lval);
}

/*
    <logical_or_tail>  -> 	or <logical_and_expr> <logical_or_tail>
                        |    ε
*/
var_t *logical_or_tail(var_t *lval)
{
    if (match(OR)) {
        var_t *rval = logical_and_expr();
        var_t *res = gen_2_op(lval, OR, rval);
        return logical_or_tail(res);
    }
    return lval;
}

/*
    <logical_and_expr> -> <equ_expr> <logical_and_tail>

*/

var_t *logical_and_expr(void)
{
    var_t *lval = equ_expr();
    return logical_and_tail(lval);
}

/*
    <logical_and_tail> -> and <equ_expr> <logical_and_tail>
                        |  ε
*/
var_t *logical_and_tail(var_t *lval)
{
    if (match(AND)) {
        var_t *rval = equ_expr();
        var_t *res = gen_2_op(lval, AND, rval);
        return logical_and_tail(res);
    }
    return lval;
}

/*
    <equ_expr> -> <relation_expr> <equ_tail>
*/
var_t *equ_expr(void)
{
    var_t *lval = relation_expr();
    equ_tail(lval);
}

/*
    <equ_tail> -> <equality_op> <relation_expr> <equ_tail>
                |  ε
    <equality_op> -> equ | nequ
*/

var_t *equ_tail(var_t *lval)
{
    if (TEST(EQU)OR(NEQU)) {
        symbol_e op = get_op();
        var_t *rval = relation_expr();
        var_t *res = gen_2_op(lval, op, rval);
        return equ_tail(res);
    }
    return lval;

}

/*
<relation_expr> ->  <add_expr> <relation_tail>
*/
var_t *relation_expr(void)
{
    var_t *lval = add_expr();
    return relation_tail(lval);
}

/*
    <relation_tail> ->  <relation_op> <add_expr> <relation_tail>
                     |   ε
    <relation_op> -> gt | ge | lt | le

*/

var_t *relation_tail(var_t *lval)
{
    if (TEST(GT) OR(GE) OR(LT) OR(LE)) {
        symbol_e op = get_op();
        var_t *rval = add_expr();
        var_t *res = gen_2_op(lval, op, rval);
        return relation_tail(res);
    }
    return lval;
}


/*
    <add_expr>   ->  <mul_expr>  <add_tail>
*/
var_t *add_expr(void)
{
    var_t *lval = mul_expr();
    return add_tail(lval);
}

/*
    <add_tail>   ->  <additive_op> <mul_expr>  <add_tail>
                  |  ε
    <additive_op> -> add | sub
*/
var_t *add_tail(var_t *lval)
{
    if (TEST(ADD)OR(SUB)) {
        symbol_e op = get_op();
        var_t *rval = mul_expr();    
        var_t *res = gen_2_op(lval, op, rval);   
        return add_tail(res);
    }
    return lval;
}



/*
    <mul_expr>   ->  <unary_expr> <mul_tail>
*/
var_t *mul_expr(void)
{
    var_t *lval = unary_expr();
    return mul_tail(lval);
}

/*
    <mul_tail>   ->  <multi_op> <unary_expr> <mul_tail>
                  |  ε
    <multi_op> ->  mul | div | mod
*/
var_t *mul_tail(var_t *lval)
{
    if (TEST(MUL) OR(DIV) OR(MOD)) {
        symbol_e op = get_op();
        var_t *rval = unary_expr();
        var_t *res = gen_2_op(lval, op, rval);	
        return mul_tail(res);
    }
    return lval;
}


/*
    <unary_expr>  -> <unary_op> <unary_expr> | <post_expr>
    <unary_op> -> incr | decr | add | sub | not | mul | lea | sizeof
*/

var_t *unary_expr(void)
{
    if (TEST(INC) OR(DEC) OR(ADD) OR(SUB) OR(NOT) OR(MUL) OR(LEA) OR(SIZEOF)) {
        symbol_e op = get_op();
        var_t *val = unary_expr();     // 递归
        return gen_1_op_left(val, op); // 左单目运算（前缀）
    }
    else
        return post_expr();
}



/*
    <post_expr> -> <primary_expr> <R>
    <R> ->  <post_op> <R> | ε
    <post_op> -> incr | decr | lbracket <expr> rbracket | lparen <realarg> rparen
*/
var_t *post_expr(void)
{
    int sym_type = 0;
    void *val = primary_expr(&sym_type);
    while (1) {
        if (TEST(INC) OR(DEC)) {
            symbol_e op = get_op();
            val = gen_1_op_right(val, op); // 右单目运算（后缀）
        } else if (TEST(LBRACKET)) {
            next_token();
            var_t *index = expr();
            val = gen_arr(val, index); // 产生数组运算表达式
            if (!match(RBRACKET))
                recovery(true, EXPECTED_RBRACKET, ERROR);  // 情况比较多，就不列举 follow 集了，报丢失
        } else if (TEST(LPAREN)) {
            // if(val == NULL) {
            //     printf("函数未定义\n");
            // }
            next_token();
            realarg(); // 参数检查；TODO  生成函数调用的代码
            if (!match(RPAREN))
                recovery(true, EXPECTED_RPAREN, ERROR); // 情况比较多，就不列举 follow 集了，报丢失
        } else {
            break;
        }
    }
    return val;
}



/*
    <realarg>	->	<arg> <arglist> | ε
*/
void realarg(void) // TODO
{
    if (EXPR_FIRST) {
        arg();
        arglist();
    }
}

// <arg> -> <expr>
void arg(void)
{
    // 实际参数
    expr();
}

/*
    <arglist>	->	comma <arg> <arglist> | ε
*/
void arglist(void)
{
    if (match(COMMA)) {
        arg();
        arglist();
    }
}

/*
<primary_expr> ->  ident | lparen <expr> rparen | <literal>
*/

void *primary_expr(int *sym_type)
{
    void *primary = NULL;
    if (TEST(ID)) { // 变量，数组名，函数名
        char name[MAX_ID_LEN + 1] = {0};
        parser_get_token_id(name);
        next_token();

        primary = get_var_or_fun(name, sym_type);
       // 用于测试
        if(*sym_type == SYMBOL_TYPE_FUN) {
            show_fun((fun_t *)primary);
        } else if(*sym_type == SYMBOL_TYPE_VAR) {
            show_var((var_t *)primary, 1);
        }

    } else if (match(LPAREN)) { // 括号表达式
        primary = expr();
        if (!match(RPAREN)) { 
            // 情况比较多，就不列举 follow 集了，报丢失
            recovery(true, EXPECTED_RPAREN, ERROR); 
        }
    } else { // 常量
        primary = literal();
    }
    return primary;
}

/*
    <literal>	->	num | string | chara
*/
var_t *literal(void)
{
    var_t *val = NULL;
    if (TEST(NUM)) {
        int num = parser_get_token_num();
        val = new_literal(&num, NUM);	
        add_literal(val); // 加入变量表
        next_token();
    } else if (TEST(CHARA)) {
        char my_ch = parser_get_token_ch();
        val = new_literal(&my_ch, CHARA);
        add_literal(val); // 加入变量表
        next_token();
    } else if (TEST(STRING)) {
        val = new_literal(parser_get_token_str(), STRING);
        add_str(val); // 加入字符串表
        next_token();
    } else {
        syn_err(EXPECTED_LITERAL_OR_EXPR, ERROR, OTHER, NULL);
    }
    return val;
}



/*
    <block>	 ->	lbraces <subprogram> rbraces
*/
void block(void)
{
    if (!match(LBRACES))
        recovery(true, EXPECTED_LBRACES, ERROR);  // 因为可能的情况太多，这里就不罗列
                                                 // follow 集了，直接报丢失。
                                 
    subprogram();

    if (!match(RBRACES))
        recovery(true, EXPECTED_RBRACES, ERROR); // 因为可能的情况太多，这里就不罗列
                                                 // follow 集了，直接报丢失。
}

/*
<subprogram>	->	<local_decl> <subprogram>
                |   <statement> <subprogram>
                |   <block>  <subprogram>
                |   ε
*/

void subprogram(void)
{
    if (TEST(INT) OR(CHAR) OR(VOID) OR(EXTERN)) { 
        local_decl();
        subprogram();
    }
    else if (STATEMENT_FIRST) { //语句
        statement();
        subprogram();
    }
    else if (TEST(LBRACES)) {
        scope_enter();
        block();
        scope_leave();
        subprogram();
    }
}

/*
<subprogram_in_switch>	->	<statement> <subprogram_in_switch>
					    |   <block>  <subprogram_in_switch>    
					    |   ε
*/
void subprogram_in_switch(void)
{
    if (STATEMENT_FIRST) { //语句
        statement();
        subprogram_in_switch();
    }
    else if (TEST(LBRACES)) {
        scope_enter();
        block();
        scope_leave();
        subprogram_in_switch();
    } else if(TEST(INT) OR(CHAR) OR(VOID) OR(EXTERN)) { 
        // 报错  need statement, not declaration
        syn_err(NEED_STATEMENT,  ERROR, OTHER, NULL);
        local_decl(); // 经测试，这样可以跳过错误代码，不影响后面的解析
        subprogram_in_switch();
    } 

}
/*
<expr_stat> -> <expr> semico
             | semico
*/
void expr_stat(void)
{
    if (EXPR_FIRST)
        expr();

    if (!match(SEMICO))
        recovery(EXPR_STAT_FOLLOW, EXPECTED_SEMICOLON, ERROR);
}



/*
<statement> -> <expr_stat>
            | <while_stat>
            | <for_stat>
            | <do_while_stat>
            | <if_stat>
            | <switch_stat>
            | <break_stat>
            | <continue_stat>
            | <return_stat>

*/

void statement(void)
{
    switch (cur_tk_g->tk) {
        case WHILE:
            while_stat();
            break;

        case FOR:
            for_stat();
            break;

        case DO:
            do_while_stat();
            break;

        case IF:
            if_stat();
            break;

        case SWITCH:
            switch_stat();
            break;

        case BREAK: /*  <break_stat> -> break semico */             
            next_token();
            if (!match(SEMICO))
                recovery(BREAK_STAT_FOLLOW, EXPECTED_SEMICOLON, ERROR); 

            break;

        case CONTINUE: /* <continue_stat> -> continue semico */                    
            next_token();
            if (!match(SEMICO))
                recovery(CONTINUE_STAT_FOLLOW, EXPECTED_SEMICOLON, ERROR); 

            break;

        case RETURN: /* <return_stat> -> return <expr_stat> */
            next_token();
            expr_stat();
            break;

        default:
            expr_stat();
            break;
    }
}

/*

 <while_stat> -> while lparen <expr> rparen <block>
              |  while lparen <expr> rparen <statement>
*/

void while_stat(void)
{
    match(WHILE);
    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR); 

    expr();

    if (!match(RPAREN))
        recovery(TEST(LBRACES)|| STATEMENT_FIRST, EXPECTED_RPAREN, ERROR);

    if (TEST(LBRACES)) { // 如果遗漏了 '{' , 会产生大片错误。gcc 也是如此
        scope_enter();
        block();
        scope_leave();
    } else {
        statement(); 
    }
}

/*
<do_while_stat> -> do <block>  while lparen <expr> rparen semico
                 | do <statement> while lparen <expr> rparen semico

*/

void do_while_stat(void)
{
    match(DO);
    if (TEST(LBRACES)) {
        scope_enter();
        block();
        scope_leave();
    } else {
        statement();
    }

    if (!match(WHILE))
        recovery(TEST(LPAREN), EXPECTED_WHILE, ERROR);

    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR);

    expr();

    if (!match(RPAREN))
        recovery(TEST(SEMICO), EXPECTED_RPAREN, ERROR);

    if (!match(SEMICO)) // 因为可能的情况太多，这里就不罗列 follow
                        // 集了，直接报丢失。
        recovery(true, EXPECTED_SEMICOLON, ERROR);
}

/*
<for_stat> 	-> 	for lparen <for_init>  <for_cond>  <for_iter> rparen  <block>
             |	for lparen <for_init>  <for_cond>  <for_iter> rparen <statement>

*/

void for_stat(void)
{
    match(FOR);
    if (!match(LPAREN))
        recovery(TYPE_FIRST || EXPR_FIRST || TEST(SEMICO), EXPECTED_LPAREN,
                 ERROR);
    scope_enter();
    for_init(); // 初始语句
    for_cond(); // 循环条件
    for_iter(); // 迭代语句

    if (!match(RPAREN))
        recovery(TEST(LBRACES)|| STATEMENT_FIRST, EXPECTED_RPAREN, ERROR);

    if (TEST(LBRACES)) {
        block();
    } else {
        statement();
    }
    scope_leave();
}
/*
<decl_head>    ->   ident | mul ident 
<for_init>     ->  <type> <decl_head> <var_decl_tail>
                |  <expr_stat>
*/
void for_init(void)
{
    if (TYPE_FIRST) {
        symbol_e my_type = type();
        char name[MAX_ID_LEN + 1] = {0};
        bool is_ptr = false;
        int line = -1; // 无效值
        if (match(MUL)) { 
            is_ptr = true;
        }
        if (TEST(ID)) {
            parser_get_token_id(name);
            line = parser_get_token_line_num();
            next_token();
        } else {
            recovery(DECL_HEAD_FOLLOW, EXPECTED_ID,
                     ERROR); // error: expected identifier
        }
        var_decl_tail(false, my_type, is_ptr, name, line);
    } else {
        expr_stat();
    }
}

/*

<for_cond> ->  <expr_stat>
*/

void for_cond(void)
{ 
    expr_stat(); 
}

/*

<for_iter> ->  <expr> | ε
*/
void for_iter(void)
{
    if (EXPR_FIRST)
        expr();
}

/*
<if_stat> -> if lparen <expr> rparen <block> <else_stat>
           | if lparen <expr> rparen <statement> <else_stat>
*/

void if_stat(void)
{
    match(IF);
    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR);

    expr();

    if (!match(RPAREN)){
        recovery(STATEMENT_FIRST OR(LBRACES), EXPECTED_RPAREN,
                 ERROR); 
    } 

    if (TEST(LBRACES)) {
        scope_enter();
        block();
        scope_leave();
    } else {
        statement();
    }

    else_stat();
}



/*

<else_stat> -> else <block>
             | else <statement>
             | ε

*/
void else_stat(void)
{
    if (match(ELSE)) {
        if (TEST(LBRACES)) {
            scope_enter();
            block();
            scope_leave();
        } else {
            statement();
        }
    }
}

/*

<switch_stat>	-> 	switch lparen <expr> rparen lbraces <case_stat> rbraces

*/

void switch_stat(void)
{
    match(SWITCH);
    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR);
    
    expr();

    if (!match(RPAREN))
        recovery(TEST(LBRACES), EXPECTED_RPAREN, ERROR);
    if (!match(LBRACES))
        recovery(TEST(CASE) OR(DEFAULT), EXPECTED_LBRACES, ERROR);
    scope_enter();
    if(SUBPROGRAM_FIRST) { // 增加健壮性，使报错更精准
        syn_err(STATEMENT_NEVER_BE_EXECUTED, ERROR, OTHER, NULL);
        subprogram();
    }
   
    case_stat();

    scope_leave();
    if (!match(RBRACES))
        recovery(SWITCH_STAT_FOLLOW, EXPECTED_RBRACES, ERROR);
}



/*
    <case_stat> 	-> 	case <case_label> colon <subprogram_in_switch> <case_stat> 
                    |   default  colon <subprogram_in_switch> <case_stat> 
                    |   ε 
*/
void case_stat(void)
{
    if (match(CASE)) {
        case_label();

        if (!match(COLON))
        recovery(STATEMENT_FIRST OR(LBRACES)OR(RBRACES)OR(CASE)OR(DEFAULT), 
                EXPECTED_COLON, ERROR);
        /*
            不能有 	<local_decl>  gcc 报错 
            error: a label can only be part of a statement 
            and a declaration is not a statement     
        */
        subprogram_in_switch(); 
        case_stat(); // 递归
    } else if (match(DEFAULT)) {
        if (!match(COLON))
            recovery(STATEMENT_FIRST OR(LBRACES)OR(RBRACES)OR(CASE)OR(DEFAULT), 
                    EXPECTED_COLON, ERROR);

        subprogram_in_switch();
        case_stat(); // 递归
    } 
}

// <case_label>	->	num | chara
void case_label(void) 
{ 
    if(TEST(NUM)OR(CHARA))
        literal(); 
    else{ 
        if (TEST(COLON)) {
             syn_err(EXPECTED_LITERAL, ERROR, OTHER, NULL);
        }
        else {
            // gcc: case label does not reduce to an integer constant
            syn_err(CASE_LABEL_NOT_INT_CONSTANT, ERROR, OTHER, NULL);
            next_token();
        }
    }
}
